<?php
/**
 * Dynamic dataobject
 *
 * @package EDO
 * @subpackage Core
 *
 */

require_once dirname(__FILE__) . '/class.DynamicEDOHelper.php';

final class EDO_object_dynamic extends EDO_object_basic
{

	// no friend classes, so they're public.
	public $_typeid;
	public $_tables;
	public $_extended_datatypes;
	public $_relations = array();

	private $_class;


	public function __construct(EDOHandler $edo_handler, $typeid)
	{
		EDO_object_base::__construct($edo_handler);

		if(!is_numeric($typeid))
		{
			$this->_typeid = $edo_handler->convert($typeid);
			$class = $typeid;
		}
		else
		{
			$this->_typeid = $typeid;
			$class = $edo_handler->convert($typeid);

		}

		$this->_class = $class;
		
		$this->_tables = DynamicEDOHelper::getTables($this);
		// $this->_tables = self::_getDynamicTables($edo_handler->ldb, $this->_typeid);

		$this->_extended_datatypes = DynamicEDOHelper::getExtendedDataTypes($this);
		// $this->_extended_datatypes = self::_getDynamicExtendedDataTypes($edo_handler->ldb, $this->_typeid);

		$this->_relations = DynamicEDOHelper::getRelations($this);
		// $this->_relations = self::_getDynamicRelations($edo_handler->ldb, $this->_typeid);

		

		$this->_typeData = DynamicEDOHelper::getTypeData($this);

        $this->_initDataTypes();



	}


	public function getClass()
	{
		return $this->_class;
	}





	/**
	 * Adds table.
	 *
	 * @param unknown_type $table_name
	 * @return unknown
	 */
	public function addTable($tableName)
	{
		
		try
		{
			$this->triggerEvent('requested_add_table', $tableName);
		}
		catch (Exception $e)
		{
			// somebody doesn't want this table to be added
			return false;
		}

		$this->ldb->beginTransaction();

		$errorfree = array();

		$phrase = "CREATE TABLE {$tableName} ( edoid integer NOT NULL REFERENCES edo_objects ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY (edoid))";

		$errorfree[] = $this->ldb->exec($phrase);

		$tableid = $this->ldb->getOne('SELECT count(tableid) FROM edo_dynamic_types_tables WHERE typeid = ' . $this->getTypeid());

		$phrase = "INSERT INTO edo_dynamic_types_tables (typeid, tableid, tablename) VALUES (" . $this->getTypeid() . ", {$tableid}, '{$tableName}')";
		$errorfree[] = $this->ldb->exec($phrase);
		
		if(in_array(false, $errorfree, true))
		{
		    
		    $this->ldb->rollback();
			return false;

		}
		else
		{
			$phrase = "INSERT INTO {$tableName} SELECT edoid FROM edo_objects WHERE typeid = {$this->getTypeid()}";
    		$this->ldb->query($phrase);

		    $this->ldb->commit();
			// $this->buildTypedata();
			$this->triggerEvent('added_table', $tableName);
			
			return true;
		}



		



	}

	/**
	 * Drops table.
	 *
	 * @param unknown_type $tableName
	 * @return unknown
	 */
	public function dropTable($tableName)
	{
	    $arrFields = $this->getTablesFields($tableName);
		foreach($arrFields as $field)
		{
			if($field != 'edoid')
			{
				$this->dropField($field);
			}
		}

		$errorfree = array();

		$this->ldb->beginTransaction();

		$phrase = "DROP TABLE {$tableName}";

		$errorfree[] = $this->ldb->exec($phrase);
		
		$phrase = "DELETE FROM edo_dynamic_types_tables WHERE tablename = '{$tableName}'";
		$errorfree[] = $this->ldb->exec($phrase);
		

		if(in_array(false, $errorfree, true))
		{
			$this->ldb->rollback();

		}
		else
		{
			$this->ldb->commit();
			#No es bueno ajaa tässä :: $this->buildTypedata();
		}

		$this->triggerEvent('onDropTable', $tableName);

		return (in_array(false, $errorfree, true)) ? false : true;



	}

	
	
	/**
	 * Adds a field.
	 *
	 * @param integer $tableid Tableid
	 * @param string $fieldName Field name
	 * @param string $fieldType Field type
	 * @param array $options Option array
	 */
	public function addField($tableid, $fieldName, $fieldType, $options = array())
	{
	   
	    
	    $fieldName = strtolower($fieldName);
		$table = $this->getTable($tableid);
		
        if($this->fieldExists($fieldName))
	       throw new Exception('Field already exists.');
		
        $this->ldb->beginTransaction();		
		
        
        
        
        
        try
        {
            $res = $table->addColumn($fieldName, $fieldType, $options);
            $this->ldb->commit();
            return true;
        }
        catch(LDB_Exception $e)
        {
            
            
            $this->ldb->rollBack();
            
            
            
            die('fu manch!');
            
            return false;
        }
        
		
        return false;
    	    
	    
	}

	

	/**
	 * Adds a field.
	 *
	 * @param unknown_type $tablename
	 * @param unknown_type $field_name
	 * @param unknown_type $field_type
	 * @param unknown_type $options
	 * @return unknown
	 */
	function oleaddField($tableid, $fieldName, $fieldType, $options = array())
	{

		
		
		die('fu mancher');
		
		if($fObj instanceof Datatype_relation AND $options)
		{
            if(	!isset($options['relation_to']) OR !is_a($options['relation_to'],'EDO_object_dynamic') OR !isset($options['relation_displayname']))
            {
            	throw new Exception('error in relation spesification');
            }

			$relationObject = $options['relation_to'];
			$displayName = $options['relation_displayname'];

			$relFields = $relationObject->getFields();
			if(!in_array($displayName,$relFields))
                throw new Exception('Nonexistent display name for relation');

			$arrData = array	(
								'typeid' => $this->getTypeid(),
								'fieldname' => $fieldName,
								'relationobject' => $relationObject->getClass(),
								'relationdisplayname'=> $displayName
								);

			if($res = $this->ldb->autoExecute('edo_dynamic_relations', $arrData, LDB::AUTOQUERY_INSERT))
			{
				$arrData = array	(
									'typeid' => $this->getTypeid(),
									'fieldname' => $fieldName,
									'fieldtype' => $fieldType
									);

				if($res = $this->ldb->autoExecute('edo_dynamic_extended_datatypes', $arrData, LDB::AUTOQUERY_INSERT))
				{
					// now change the field type to integer so that we can insert the relation
					$fieldType = "integer";
					unset($options['relation_to']);
					unset($options['relation_displayname']);
					$res = $table->addColumn($fieldName, $fieldType, $options);
				}
			}
			if(!$res)
			{ // if there was error(s) during operation
				#$this->ldb->rollback();

				

				$this->ldb->query("DELETE FROM edo_dynamic_relations WHERE typeid={$this->getTypeid()} AND fieldname='{$fieldName}'");
				$this->ldb->query("DELETE FROM edo_dynamic_extended_datatypes WHERE typeid={$this->getTypeid()} AND fieldname='{$fieldName}'");
				throw new Exception('creation of relation tables failed');
			}
			else
			{
				#$this->ldb->commit();
				// $this->buildTypedata();
				$this->triggerEvent('onAddField',array('table'=>$table->getName(),'field'=>$fieldName));
				return true;
			}
		}
		elseif("Datatype_base" != get_parent_class($fObj)) // not any of the base types
		{
			$darray = array();
			$darray['typeid'] = $this->getTypeid();
			$darray['fieldname'] = $fieldName;
			$darray['fieldtype'] = $fObj->getType();

			$this->ldb->autoExecute('edo_dynamic_extended_datatypes', $darray, LDB::AUTOQUERY_INSERT);

		}

		if(!$options)
		{
			$options = $fObj->getConfig();
		}



		$res = $table->addColumn($fieldName, $fieldType, $options);


		if($res)
		{
			// $this->buildTypedata();
			$this->triggerEvent('onAddField',array('table'=>$table->getName(),'field'=>$fieldName));
		}

		return $res;
	}

	/**
	 * Drops a field.
	 *
	 * @param unknown_type $col_name
	 * @return unknown
	 */
	function dropField($colName)
	{
        
        // the famous 'three Ds' solution
        LEAD::requirePackage('EDO/Core/DynamicDatatypeDeletor');;
        $fObj = $this->getFieldObject(strtolower($colName));
        if($fObj)
        {
            
            $errorfree = array();
            $this->ldb->beginTransAction();
            $errorfree[] = $this->ldb->exec("DELETE FROM edo_dynamic_extended_datatypes WHERE typeid={$this->getTypeid()} AND fieldname='{$fObj->getName()}'");

            $tableName = $this->getFieldsTable($fObj->getName());
            
            
            
            
            if($tableName)
            {
                $table = $this->ldb->getTable($tableName);
                $errorfree[] = $table->dropColumn($fObj->getName());

            }
          
                       
           $errorfree[] = DynamicDatatypeDeletor::delete($fObj);
                                               
                                    
            if(!in_array(false, $errorfree, true))
            {
                $this->ldb->commit();
                $this->triggerEvent('onDropField', $fObj);
                return true;
            }
            
            $this->ldb->rollBack();           
            return false;
        }
        
        
        
        return false;
		
	}

	
	public function getMeta($metakey, $default = false)
	{
	    return (isset($this->_typeData['meta'][$metakey])) ? $this->_typeData['meta'][$metakey] : $default;
	}
	
	

}